﻿// --------------------------------------------------------------------------------------------------------------------
// <copyright company="Microsoft Corp." file="TestSqlAzureManagementWebResponseFactory.cs">
//   All rights reserved. See License.txt in the project root for license information.
// </copyright>
// 
// --------------------------------------------------------------------------------------------------------------------
namespace AzureManagementTests.TestSupport
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Net;

    using AzureManagement;
    using AzureManagement.SqlAzureDataContracts;

    using Common;

    public class TestSqlAzureManagementWebResponseFactory : ITestWebResponseFactory
    {
        public string BaseUri { get; set; }

        public string ApiVersion { get; set; }

        public string SubscriptionId { get; set; }

        public IList<string> ManagementCertificates { get; set; }

        public IList<SqlAzureServerMock> Servers { get; set; }

        public WebResponse CreateResponse(TestWebRequest request)
        {
            if (string.IsNullOrEmpty(request.CertificateThumbprint) || this.ManagementCertificates == null
                || !this.ManagementCertificates.Any(x => x.Equals(request.CertificateThumbprint)))
            {
                return new TestWebResponse("Invalid request.");
            }

            string body = request.GetBody();

            var versionHeader = request.Headers.Get("x-ms-version");
            if (string.IsNullOrEmpty(versionHeader) || !versionHeader.Equals(this.ApiVersion))
            {
                return new TestWebResponse("Api version is not specified.");
            }

            if (
                !this.BaseUri.Equals(
                    string.Format(
                        "{0}://{1}:{2}/", 
                        request.RequestUri.Scheme, 
                        request.RequestUri.DnsSafeHost, 
                        request.RequestUri.Port)))
            {
                return new TestWebResponse("Invalid base Uri.");
            }

            var segments =
                request.RequestUri.AbsolutePath.Split(new[] { "/" }, StringSplitOptions.RemoveEmptyEntries).ToList();
            if (!segments.Any())
            {
                return new TestWebResponse("Invalid request uri.");
            }

            if ((request.Method.Equals("POST") || request.Method.Equals("PUT")) && !string.IsNullOrEmpty(body)
                && !request.ContentType.Equals("application/xml"))
            {
                return new TestWebResponse("Invalid content type.");
            }

            if (!segments.First().Equals(this.SubscriptionId))
            {
                return new TestWebResponse("Invalid subscription id");
            }

            segments.RemoveAt(0);
            if (!segments.Any())
            {
                return new TestWebResponse("Invalid request uri.");
            }

            if (segments.First().Equals("servers"))
            {
                segments.RemoveAt(0);
                return this.ProcessSqlServerManagementRequest(segments, request.Method, body, request.RequestUri.Query);
            }

            return new TestWebResponse("Invalid request.");
        }

        private TestWebResponse ProcessSqlServerManagementRequest(
            IList<string> segments, string method, string body, string query)
        {
            if (!segments.Any())
            {
                if (method.Equals("POST"))
                {
                    var createSqlServer = XmlHelper.Deserialize<CreateSqlAzureServer>(body);
                    if (this.ValidateSqlServer(createSqlServer))
                    {
                        var server = new SqlAzureServer
                                         {
                                             Name = Guid.NewGuid().ToString(), 
                                             AdministratorLogin = createSqlServer.AdministratorLogin, 
                                             Location = createSqlServer.Location
                                         };

                        this.Servers.Add(new SqlAzureServerMock { Server = server });

                        var response = @"<?xml version=""1.0"" encoding=""utf-8""?>
                                        <ServerName xmlns=""http://schemas.microsoft.com/sqlazure/2010/12/"">"
                                       + server.Name + "</ServerName>";

                        return new TestWebResponse(response);
                    }
                }

                if (method.Equals("GET"))
                {
                    return this.ListSqlServers();
                }
            }

            var serverName = segments.First();
            segments.RemoveAt(0);

            if (!this.Servers.Any(x => x.Server.Name.Equals(serverName)))
            {
                return new TestWebResponse("Invalid sql server name.");
            }

            var sqlServer = this.Servers.First(x => x.Server.Name.Equals(serverName));
            if (!segments.Any() && method.Equals("DELETE"))
            {
                this.Servers.Remove(sqlServer);
                return new TestWebResponse("Server has been deleted.");
            }

            if (segments.First().Equals("firewallrules"))
            {
                segments.RemoveAt(0);

                var ruleName = Uri.UnescapeDataString(segments.First());
                segments.RemoveAt(0);
                if (!string.IsNullOrEmpty(ruleName) && !segments.Any()
                    && (method.Equals("PUT") || method.Equals("POST")))
                {
                    if (query.Contains("op=AutoDetectClientIP"))
                    {
                        var rule = new FirewallRule
                        {
                            StartIpAddress = "157.55.3.0",
                            EndIpAddress = "157.55.3.24"
                        };

                        sqlServer.Rules.Add(new FirewallRuleMock
                        {
                            Name = ruleName, 
                            Rule = rule
                        });
                    }
                    else
                    {
                        var rule = XmlHelper.Deserialize<FirewallRule>(body);
                        if (this.ValidateFirewallRule(rule))
                        {
                            sqlServer.Rules.Add(new FirewallRuleMock { Name = ruleName, Rule = rule });
                        }
                    }

                    return new TestWebResponse("<IpAddress>192.168.13.144</IpAddress>");
                }
            }

            return new TestWebResponse("Invalid request.");
        }

        private bool ValidateFirewallRule(FirewallRule rule)
        {
            if (rule == null)
            {
                return false;
            }

            return !string.IsNullOrEmpty(rule.StartIpAddress) && !string.IsNullOrEmpty(rule.EndIpAddress);
        }

        private TestWebResponse ListSqlServers()
        {
            var servers = new SqlAzureServers { Items = this.Servers.Select(x => x.Server).ToList() };
            return new TestWebResponse(XmlHelper.Serialize(servers));
        }

        private bool ValidateSqlServer(CreateSqlAzureServer createSqlServer)
        {
            if (createSqlServer == null)
            {
                return false;
            }

            return !string.IsNullOrEmpty(createSqlServer.AdministratorLogin)
                   && !string.IsNullOrEmpty(createSqlServer.AdministratorLoginPassword)
                   && !string.IsNullOrEmpty(createSqlServer.Location);
        }
    }
}